using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace Firefly.Framework.Input
{
    public class InputService : IUpdateable
    {
        private GamePadManagerCollection _gamePadManagerCollection;

        public KeyboardManager KeyboardManager { get; private set; }
        public MouseManager MouseManager { get; private set; }
        
        public GamePadManager GamePadManager(PlayerIndex playerIndex)
        {
            switch (playerIndex)
            {
                case PlayerIndex.One:
                    return _gamePadManagerCollection.GamePadOne;
                case PlayerIndex.Two:
                    return _gamePadManagerCollection.GamePadTwo;
                case PlayerIndex.Three:
                    return _gamePadManagerCollection.GamePadThree;
                case PlayerIndex.Four:
                    return _gamePadManagerCollection.GamePadFour;
            }

            return null;
        }

        public void RegisterInputMap(IInputMap map)
        {
            switch(map.InputMapType)
            {
                case InputMapType.KeyMap:
                    KeyboardManager.RegisterInputMap(map);
                    break;
                case InputMapType.MouseButtonMap:
                case InputMapType.MouseAxisMap:
                case InputMapType.MouseScrollWheelMap:
                    MouseManager.RegisterInputMap(map);
                    break;
                case InputMapType.GamePadButtonMap:
                case InputMapType.GamePadDPadMap:
                case InputMapType.GamePadThumbStickMap:
                case InputMapType.GamePadTriggerMap:
                    IGamePadMap gamePadMap = map as IGamePadMap;
                    _gamePadManagerCollection.GetGamePad(gamePadMap.PlayerIndex).RegisterInputMap(map);
                    break;
            }
        }

        #region Threadsafe Singleton

        public static InputService Instance
        {
            get { return Nested._instance; }
        }

        private class Nested
        {
            internal static readonly InputService _instance = new InputService();

            static Nested() { }
        }

        private InputService()
        {
            Enabled = true;
            UpdateOrder = 0;
            KeyboardManager = new KeyboardManager();
            MouseManager = new MouseManager();
            _gamePadManagerCollection = new GamePadManagerCollection();
        }

        #endregion
        
        #region IUpdateable Members

        public event EventHandler EnabledChanged;
        public event EventHandler UpdateOrderChanged;

        private bool _enabled;
        private int _updateOrder;

        public bool Enabled
        {
            get { return _enabled; }
            set
            {
                if (value != _enabled)
                {
                    _enabled = value;
                    NotifyEnabledChanged();
                }
            }
        }
        public int UpdateOrder
        {
            get { return _updateOrder; }
            set
            {
                if (value != _updateOrder)
                {
                    _updateOrder = value;
                    NotifyUpdateOrderChanged();
                }
            }
        }

        private void NotifyEnabledChanged()
        {
            EventHandler handler = EnabledChanged;

            if (handler != null)
            {
                handler(this, new EventArgs());
            }
        }

        private void NotifyUpdateOrderChanged()
        {
            EventHandler handler = UpdateOrderChanged;

            if (handler != null)
            {
                handler(this, new EventArgs());
            }
        }

        public void Update(GameTime gameTime)
        {
            if (Enabled)
            {
                KeyboardManager.Update(gameTime);
                MouseManager.Update(gameTime);
                _gamePadManagerCollection.Update(gameTime);
            }
        }

        #endregion
    }
}
